`include "defines.svh"
`include "CP0Defines.svh"
`include "CacheDefines.svh"
module WrControl (
    input logic PREIF_IF_Flush_Exception,
    input logic IF_ID_Flush_Exception,
    input logic ID_EXE_Flush_Exception,
    input logic EXE_MEM_Flush_Exception,

    input logic DH_IF_PCWr,
    input logic DH_IF_IDWr,
    input logic ID_EXE_Flush_DH,
    input logic mfc0_DH,
    input logic Side_DH,

    input logic EXE_Prediction_Failed,
    input logic EXE_IsTaken,
    input logic EXE_PF_FlushAll,
    
    input logic EXE_ALU2_Stall,
    input logic [1:0]IsExceptionorEret,

    input logic cpu_ibus_busy,
    input logic cpu_dbus_busy,

    output logic PREIF_PCWr,
    output logic RF_CantWr,
    output logic PREIF_IF_Stall,
    output logic IF_ID_Stall,
    output logic ID_EXE_Stall,
    output logic EXE_MEM_Stall,
    output logic MEM_MEM2_Stall,
    output logic MEM2_WB_Stall,

    output logic PREIF_IF_Flush,
    output logic IF_ID_Flush,
    output logic ID_EXE_Flush,
    output logic EXE_MEM_Flush,
    output logic MEM_MEM2_Flush,
    output logic MEM2_WB_Flush,
    output logic HiLo_Not_Flush

);
    logic Exception;
    assign Exception = PREIF_IF_Flush_Exception;
    assign MEM2_WB_Flush = 1'b0;
    assign MEM_MEM2_Flush = 1'b0;


    always_comb begin  
        if(Exception == 1'b1)begin
            if(cpu_ibus_busy)
                PREIF_PCWr = 1'b0;
            else
                PREIF_PCWr = 1'b1;
        end
        else if(cpu_ibus_busy||cpu_dbus_busy)
            PREIF_PCWr = 1'b0;
        else if(Side_DH)
            PREIF_PCWr = 1'b0;
        else if(ID_EXE_Flush_DH)
            PREIF_PCWr = 1'b0;
        else if(mfc0_DH)
            PREIF_PCWr = 1'b0;
        else if(EXE_Prediction_Failed==1'b1)
            PREIF_PCWr = 1'b1;
        else begin
            if(DH_IF_PCWr == 1'b0 || EXE_ALU2_Stall == 1'b1)
                PREIF_PCWr = 1'b0;
            else 
                PREIF_PCWr = 1'b1;
        end
    end

    always_comb begin
        if(Exception == 1'b1)begin
            if(cpu_ibus_busy)begin
                PREIF_IF_Stall = 1'b1;
                IF_ID_Stall = 1'b1;

                PREIF_IF_Flush = 1'b0;
                IF_ID_Flush = 1'b0;
            end
            else begin
                PREIF_IF_Stall = 1'b0;
                IF_ID_Stall = 1'b0;

                PREIF_IF_Flush = 1'b1;
                IF_ID_Flush = 1'b1;
            end
        end
        else if(cpu_dbus_busy||cpu_ibus_busy)begin
            PREIF_IF_Stall = 1'b1;
            IF_ID_Stall = 1'b1;

            PREIF_IF_Flush = 1'b0;
            IF_ID_Flush = 1'b0;
        end
        else if(Side_DH)begin
            PREIF_IF_Stall = 1'b1;
            IF_ID_Stall = 1'b1;

            PREIF_IF_Flush = 1'b0;
            IF_ID_Flush = 1'b0;
        end
        else if(ID_EXE_Flush_DH == 1'b1)begin
            PREIF_IF_Stall = 1'b1;
            IF_ID_Stall = 1'b1;

            PREIF_IF_Flush = 1'b0;
            IF_ID_Flush = 1'b0;
        end
        else if(mfc0_DH)begin
            PREIF_IF_Stall = 1'b1;
            IF_ID_Stall = 1'b1;

            PREIF_IF_Flush = 1'b0;
            IF_ID_Flush = 1'b0;
        end
        else if(EXE_Prediction_Failed==1'b1||EXE_PF_FlushAll==1'b1)begin
            PREIF_IF_Stall = 1'b0;
            IF_ID_Stall = 1'b0;

            PREIF_IF_Flush = 1'b1;
            IF_ID_Flush = 1'b1;
        end
        else begin
            if(DH_IF_PCWr == 1'b0 ||EXE_ALU2_Stall == 1'b1)begin
                PREIF_IF_Stall = 1'b1;
                IF_ID_Stall = 1'b1;

                PREIF_IF_Flush = 1'b0;
                IF_ID_Flush = 1'b0;
            end
            else begin
                PREIF_IF_Stall = 1'b0;
                IF_ID_Stall = 1'b0;

                PREIF_IF_Flush = 1'b0;
                IF_ID_Flush = 1'b0;
            end
        end
    end

    always_comb begin
        if(Exception == 1'b1)begin
            if(cpu_ibus_busy)begin
                ID_EXE_Stall = 1'b1;

                ID_EXE_Flush = 1'b0;
            end
            else begin
                ID_EXE_Stall = 1'b0;  

                ID_EXE_Flush = 1'b1;
            end
        end
        else if(cpu_dbus_busy||cpu_ibus_busy)begin
            ID_EXE_Stall = 1'b1;

            ID_EXE_Flush = 1'b0;
        end
        else if(mfc0_DH)begin
            ID_EXE_Stall = 1'b1;

            ID_EXE_Flush = 1'b0;
        end
        else if(Side_DH)begin
            ID_EXE_Stall = 1'b1;

            ID_EXE_Flush = 1'b0;
        end
        else if(ID_EXE_Flush_DH)begin
            ID_EXE_Stall = 1'b0;

            ID_EXE_Flush = 1'b1;
        end
        else if(EXE_PF_FlushAll)begin
            ID_EXE_Stall = 1'b0;

            ID_EXE_Flush = 1'b1;
        end
        else begin
            if(EXE_ALU2_Stall == 1'b1)begin
                ID_EXE_Stall = 1'b1;

                ID_EXE_Flush = 1'b0;
            end
            else begin 
                ID_EXE_Stall = 1'b0;

                ID_EXE_Flush = 1'b0;
            end
        end
    end

    always_comb begin
        if(Exception == 1'b1)begin
            if(cpu_ibus_busy)begin
                EXE_MEM_Stall = 1'b1;
                MEM_MEM2_Stall = 1'b1;

                EXE_MEM_Flush = 1'b0;
            end
            else begin
                EXE_MEM_Stall = 1'b0; 
                MEM_MEM2_Stall = 1'b0; 

                EXE_MEM_Flush = 1'b1;
            end
        end
        else if(cpu_dbus_busy||cpu_ibus_busy)begin
            EXE_MEM_Stall = 1'b1;
            MEM_MEM2_Stall = 1'b1;

            EXE_MEM_Flush = 1'b0;
        end
        else if(mfc0_DH)begin
            EXE_MEM_Stall = 1'b0;
            MEM_MEM2_Stall = 1'b0;

            EXE_MEM_Flush = 1'b1;
        end
        else if(Side_DH)begin
            EXE_MEM_Stall = 1'b0;
            MEM_MEM2_Stall = 1'b0;

            EXE_MEM_Flush = 1'b1;
        end
        else begin
            EXE_MEM_Stall = 1'b0;
            MEM_MEM2_Stall = 1'b0;

            EXE_MEM_Flush = 1'b0;
        end
    end

    always_comb begin
         if(Exception == 1'b1)begin
            if(cpu_ibus_busy)
                MEM2_WB_Stall = 1'b1;
            else
                MEM2_WB_Stall = 1'b0;  
        end  
        else if(cpu_dbus_busy||cpu_ibus_busy)
            MEM2_WB_Stall = 1'b1;
        else if(mfc0_DH)
            MEM2_WB_Stall = 1'b0; 
        else if(Side_DH)
            MEM2_WB_Stall = 1'b0;
        else 
            MEM2_WB_Stall  = 1'b0;
    end

    always_comb begin
        if(EXE_MEM_Flush_Exception == 1'b1)
            if(cpu_ibus_busy)
                RF_CantWr = 1'b1;
            else    
                RF_CantWr = 1'b0;
        else if(cpu_dbus_busy||cpu_ibus_busy)
            RF_CantWr = 1'b1;
        else 
            RF_CantWr = 1'b0;
    end

    always_comb begin
        if (IsExceptionorEret != '0 || EXE_MEM_Stall) begin
            HiLo_Not_Flush = '0;
        end
        else begin
            HiLo_Not_Flush = '1;
        end
    end
endmodule
